/*
 * Copyright (C) 2025 Tsingteng MicroSystem
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/**
 * @file rw_t2t.c
 * @brief T2T Tag implementation
 */

#include "nci_feature.h"
#if IS_FEATURE_ON(NCI_FEATURE_RW_T2T)

#include "rw_tag.h"
#include "nci_data.h"
#include "nfc_log_api.h"
#include "nfc_hex_utils.h"
#include "rw_int.h"
#include "rw_utils.h"
#include "nfa_rw.h"
#include "discover_int.h"
#include "nfa_rw_t2t.h"

#define T2T_CMD_READ 0x30
#define T2T_CMD_WRITE 0xA2
#define T2T_CMD_SEC_SEL 0xC2

#define T2T_CMD_LEN_READ 2
#define T2T_CMD_LEN_WRITE 6
#define T2T_CMD_LEN_SEC_SEL 4

#define T2T_RSP_LEN_READ 16
#define T2T_RSP_LEN_WRITE 1
#define T2T_RSP_LEN_SEC_SEL 1

#define T2T_ACK 0x0A

#define T2T_BYTES_PRE_BLOCK 4
#define T2T_BLOCKS_PRE_PAGE 4
#define T2T_BYTES_PRE_PAGE 16
#define T2T_BLOCKS_PRE_SECTOR 0x100

#define T2T_BLNO_HEAD 0x00
#define T2T_BLNO_CC 0x03
#define T2T_BLNO_AREA 0x04

#define T2T_CC0_NMN_BYTE 0x0C
#define T2T_CC1_VNO_BYTE 0x0D
#define T2T_CC2_TMS_BYTE 0x0E
#define T2T_CC3_RWA_BYTE 0x0F

#define T2T_STATIC_LOCK0_BYTE 0x0A
#define T2T_STATIC_LOCK1_BYTE 0x0B

#define T2T_STATIC_LOCK_READ_ONLY 0xFF

#define T2T_HDR_SIZE T2T_BYTES_PRE_PAGE
#define T2T_AREA_STATIC_SIZE 48
#define T2T_STATIC_SIZE 0x40

#define T2T_BYTES_PRE_ATTR_BYTE_CTRL 8 // 每一个attr字节控制8字节
#define BITS_PER_BYTE 8

#define T2T_CC_BLOCK_NO 0x03
#define T2T_AREA_FIRST_BLOCK_NO 0x04

#define T2T_CC0_NMN 0xE1 // NDEF Magic Number
#define T2T_CC1_VNO 0x11
#define T2T_CC1_VNO_LEGACY 0x10
#define T2T_CC1_VNO_NEW 0x12
#define T2T_CC2_TMS_STATIC 0x06
#define T2T_CC3_RWA_RW 0x00
#define T2T_CC3_RWA_RO 0x0F

#define T2T_TLV_NULL 0x00
#define T2T_TLV_LOCK 0x01
#define T2T_TLV_MEM 0x02
#define T2T_TLV_NDEF 0x03
#define T2T_TLV_TERM 0xFE

#define T2T_TLV_LEN_LOCK 0x03


#define T2T_TAG_MUL_MID 0x04
#define T2T_TAG_INFINEON_MID 0x05
#define T2T_TAG_KOVIO_MID 0x37
#define T2T_TAG_BRCM_MID 0x2E

#define T2T_VER_BLOCK_M1 0x04
#define T2T_VER_BLOCK_INFINEON 0x00
#define T2T_VER_BLOCK_BRCM 0x00

#define T2T_VER_NO_MUL 0xFFFF
#define T2T_VER_NO_MUL_FAMILY 0x0200
#define T2T_VER_NO_INFINEON_MYD_MOVE_LEAN 0x0570
#define T2T_VER_NO_INFINEON_MYD_MOVE 0x0530
#define T2T_VER_NO_BRCM_STATIC_MEM 0x2E01
#define T2T_VER_NO_BRCM_DYNAMIC_MEM 0x2E02

#define T2T_DEFAULT_LOCK_BLPB 3

#define T2T_ATQA_MUL 0x4400
#define T2T_SAK_00 0x00
#define T2T_SAK_04 0x04

#if IS_FEATURE_ON(NCI_FEATURE_RW_NDEF)

/**
 * @brief T2T Tag初始化相关数据配置
 */
typedef struct {
    /** @brief 卡片制造厂商ID，T2T卡片第一个byte */
    uint8_t manufacturer_id;
    /**
     * @brief 表示此种卡片是否存在多种版本
     *
     * @note 如果为true，则需要读取版本号并进行比较才能确认是否是此类型卡片
     * @note 如果为false，则不需要读取版本号，直接通过manufacturer_id判断是否是此类型卡片
     */
    bool is_multi_version;
    /** @brief 存储version信息的block号 */
    uint8_t version_block;
    /** @brief 本类型卡片的version编号 */
    uint16_t version_no;
    /** @brief version的mask */
    uint16_t version_mask;
    /**
     * @brief 表示此种卡片是否需要动态计算CC2的TMS字段大小
     *
     * @note 如果为true，则需要根据version后面的字段进一步计算TMS字段大小
     * @note 否则，直接使用tms字段的值
     */
    bool calc_cc;
    /** @brief 此种卡片CC2的TMS值 */
    uint8_t tms;
    /** @brief 是否是one program tag */
    bool is_opt;
    /** @brief 此种卡片每个lock bit锁定多少byte */
    uint8_t bytes_locked_pre_lock_bit;
} tT2T_INIT_TAG;

/**
 * @brief 当前支持的T2T Tag初始化相关数据配置
 */
static tT2T_INIT_TAG s_t2t_init_tags[] = {
    {T2T_TAG_MUL_MID, true, T2T_VER_BLOCK_M1, T2T_VER_NO_MUL, 0xFFFF, false, 0x06, false, T2T_DEFAULT_LOCK_BLPB},
    {T2T_TAG_MUL_MID, true, T2T_VER_BLOCK_M1, T2T_VER_NO_MUL_FAMILY, 0xFFFF, true, 0x00, false, T2T_DEFAULT_LOCK_BLPB},
    {T2T_TAG_KOVIO_MID, false, 0x00, 0x00, 0x0000, false, 0x1D, true, 0x04},
    {T2T_TAG_INFINEON_MID, true, T2T_VER_BLOCK_INFINEON, T2T_VER_NO_INFINEON_MYD_MOVE_LEAN, 0xFFF0, false, 0x06, false, T2T_DEFAULT_LOCK_BLPB},
    {T2T_TAG_INFINEON_MID, true, T2T_VER_BLOCK_INFINEON, T2T_VER_NO_INFINEON_MYD_MOVE, 0xFFF0, false, 0x10, false, T2T_DEFAULT_LOCK_BLPB},
    {T2T_TAG_BRCM_MID, true, T2T_VER_BLOCK_BRCM, T2T_VER_NO_BRCM_STATIC_MEM, 0xFFFF, false, 0x06, false, T2T_DEFAULT_LOCK_BLPB},
    {T2T_TAG_BRCM_MID, true, T2T_VER_BLOCK_BRCM, T2T_VER_NO_BRCM_DYNAMIC_MEM, 0xFFFF, false, 0x3C, false, T2T_DEFAULT_LOCK_BLPB},
};

#define T2T_INIT_TAGS_SIZE 7

const static uint8_t s_t2t_mask_bits[] = {
    0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80
};

#endif // IS_FEATURE_ON(NCI_FEATURE_RW_NDEF)

/**
 * @brief T2T Tag info
 */
typedef struct {
    /** @brief 是否执行了NDEF检测 */
    bool is_ndef_detected;
    /** @brief 记录当前sector编号 */
    uint8_t curr_sec_no;
    /** @brief 记录第一个page内容 */
    uint8_t hdr[T2T_BYTES_PRE_PAGE];
    /** @brief HDR+T2T Area的总大小 */
    uint16_t max_size;
    /** @brief 是否static lock启用了 */
    bool is_static_locked;
    /** @brief 是否忽略NAK检查 */
    bool skip_check_nak;
#if IS_FEATURE_ON(NCI_FEATURE_RW_NDEF)
    /** @brief attr的长度 */
    uint16_t attr_len;
    /**
     * @brief 记录从block4到T2T Area结束的每个byte是否是保留（不能用于读写NDEF数据的）
     *
     * @note attr中每个byte的一个bit控制一个byte是否是保留，如果为1，则该byte不能用于读写NDEF数据
     * @note attr中每个byte可以控制8个byte, 也就是两个T2T Block
     *
     * @example attr[1] = 0b00000110, 表示第6个block的中间两个byte是保留的
     */
    uint8_t *attr;
    /** @brief 记录lock bits的起始地址 */
    uint16_t lock_bits_start;
    /** @brief 记录lock bits的长度（bit数量）*/
    uint8_t lock_bits_count;
    /** @brief lock_attr的长度 */
    uint16_t lock_attr_len;
    /**
     * @brief 记录从Static T2T Area结束的下一个block(block:0x10)开始到T2T Area结束的每个byte是否是只读的
     *
     * @note lock_attr中每个byte的一个bit控制一个byte是否是只读的，如果为1，则该byte是只读的
     * @note lock_attr中每个byte可以控制8个byte, 也就是两个T2T Block
     *
     * @example lock_attr[1] = 0b00000110, 表示第6个block的中间两个byte是只读的
     */
    uint8_t *lock_attr;
    /** @brief 记录NDEF LEN Filed起始的偏移量 */
    uint16_t ndef_len_start;
    /** @brief 记录NDEF Value Filed起始的偏移量 */
    uint16_t ndef_value_start;
    /** @brief 记录NDEF Value最大的长度 */
    uint16_t ndef_value_len;
    /** @brief 记录能够写入的NDEF最大长度 */
    uint16_t ndef_max_size;
    /** @brief 保存NDEF Flags */
    uint8_t ndef_flags;
    /** @brief 记录NDEF数据的第一个block数据 */
    uint8_t ndef_first_block[T2T_BYTES_PRE_BLOCK];
    /** @brief 记录卡片是否能够格式化成NDEF格式 */
    bool is_ndef_formatable;
#endif // IS_FEATURE_ON(NCI_FEATURE_RW_NDEF)
} tT2T_INFO;

static tT2T_INFO s_t2t_info;

/**
 * @brief 选择T2T Sector
 *
 * @param sector 切换到哪个sector
 * @param pp_rsp 返回的响应数据
 *
 * @return 成功返回NCI_STATUS_OK, 失败返回其他错误码
 */
static tNCI_STATUS t2t_sector_select(uint8_t sector, tNCI_BUF **pp_rsp) {
    tNCI_BUF *cmd = alloc_nci_buf_with_cap(0, T2T_CMD_LEN_SEC_SEL);
    tNCI_BUF *rsp = *pp_rsp;
    tNCI_STATUS ret = NCI_STATUS_EXT_FAILED;
    if (rsp) {
        reset_nci_buf(rsp);
    } else {
        rsp = alloc_nci_buf_with_cap(0, T2T_RSP_LEN_SEC_SEL);
    }

    if (!cmd || !rsp) {
        NFCLOG_E("alloc_nci_buf failed");
        ret = NCI_STATUS_EXT_ALLOC_FAILED;
        goto failed;
    }

    // 发送sector select命令
    UINT8_TO_BUF(cmd, T2T_CMD_SEC_SEL);
    UINT8_TO_BUF(cmd, 0xFF);

    ret = rw_transmit(cmd, rsp);
    if (ret != NCI_STATUS_OK) {
        NFCLOG_E("rw_transmit failed, ret=%d", ret);
        goto failed;
    }
    if (rsp->len != T2T_RSP_LEN_SEC_SEL) {
        ret = NCI_STATUS_EXT_FAILED;
        NFCLOG_E("sector select failed, len=%d", rsp->len);
        goto failed;
    }
    if (rsp->data[0] != T2T_ACK) {
        ret = NCI_STATUS_EXT_FAILED;
        NFCLOG_E("sector select failed, nak=0x%02X", rsp->data[0]);
        goto failed;
    }

    reset_nci_buf(cmd);

    // 发送选择的sector号，不等待响应
    UINT8_TO_BUF(cmd, sector);
    UINT8_TO_BUF(cmd, 0x00);
    UINT8_TO_BUF(cmd, 0x00);
    UINT8_TO_BUF(cmd, 0x00);

    ret = rf_transmit_async(cmd);
    if (ret != NCI_STATUS_OK) {
        NFCLOG_E("rf_transmit_async failed, ret=%d", ret);
        goto failed;
    }

    s_t2t_info.curr_sec_no = sector;
    *pp_rsp = rsp;
    goto cleanup;
failed:
    free_nci_buf(rsp);
    *pp_rsp = NULL;
cleanup:
    free_nci_buf(cmd);
    return ret;
}

/**
 * @brief 读取T2T Page（16 byte）
 *
 * @param bl_addr 读取起始地址block编号
 * @param pp_rsp 返回的响应数据
 *
 * @return 成功返回NCI_STATUS_OK, 失败返回其他错误码
 */
static tNCI_STATUS t2t_read_page(uint16_t bl_addr, tNCI_BUF **pp_rsp) {
    if (!pp_rsp) {
        return NCI_STATUS_EXT_INVALID_PARAM;
    }
    tNCI_BUF *cmd = alloc_nci_buf_with_cap(0, T2T_CMD_LEN_READ);
    tNCI_BUF *rsp = *pp_rsp;
    tNCI_STATUS ret = NCI_STATUS_EXT_FAILED;
    if (!rsp) {
        rsp = alloc_nci_buf_with_cap(0, T2T_RSP_LEN_READ);
    } else {
        reset_nci_buf(rsp);
    }
    if (!cmd || !rsp) {
        NFCLOG_E("alloc_nci_buf failed");
        ret = NCI_STATUS_EXT_ALLOC_FAILED;
        goto failed;
    }

    tT2T_INFO *p_t2t = &s_t2t_info;

    uint8_t blno = bl_addr % T2T_BLOCKS_PRE_SECTOR;
    uint8_t sec_no = bl_addr / T2T_BLOCKS_PRE_SECTOR;

    if (sec_no != p_t2t->curr_sec_no) {
        // 当前sector和目标sector不一致，需要先切换到目标sector
        ret = t2t_sector_select(sec_no, &rsp);
        if (ret != NCI_STATUS_OK) {
            NFCLOG_E("t2t_sector_select failed, ret=%d", ret);
            goto failed;
        }
    }

    UINT8_TO_BUF(cmd, T2T_CMD_READ);
    UINT8_TO_BUF(cmd, blno);
    s_t2t_info.skip_check_nak = true;
    uint8_t retry_count = 0;
    do {
        ret = rw_transmit(cmd, rsp);
        s_t2t_info.skip_check_nak = false;
        if (ret != NCI_STATUS_OK) {
            NFCLOG_E("rw_transmit failed, ret=%d", ret);
            goto failed;
        }
        if (rsp->len == 1 && (rsp->data[0] & 0x0F) != T2T_ACK) {
            NFCLOG_W("read block failed, nak=0x%02X, retry once", rsp->data[0]);
            continue;
        }
        if (rsp->len != T2T_RSP_LEN_READ) {
            ret = NCI_STATUS_EXT_FAILED;
            NFCLOG_E("read page failed, len=%d", rsp->len);
            goto failed;
        }
        break;
    } while(retry_count++ < 1);
    *pp_rsp = rsp;
    goto cleanup;
failed:
    free_nci_buf(rsp);
    *pp_rsp = NULL;
cleanup:
    free_nci_buf(cmd);
    return ret;
}

static void reset_t2t_info() {
    tT2T_INFO *p_t2t = &s_t2t_info;
#if IS_FEATURE_ON(NCI_FEATURE_RW_NDEF)
    if (p_t2t->attr) {
        osi_free(p_t2t->attr);
    }
    p_t2t->attr = NULL;
    if (p_t2t->lock_attr) {
        osi_free(p_t2t->lock_attr);
    }
    p_t2t->lock_attr = NULL;
#endif // IS_FEATURE_ON(NCI_FEATURE_RW_NDEF)
    bool is_ndef_formatable = p_t2t->is_ndef_formatable;
    osi_memset_s(p_t2t, sizeof(tT2T_INFO), 0, sizeof(tT2T_INFO));
    p_t2t->is_ndef_formatable = is_ndef_formatable;
}

#if IS_FEATURE_ON(NCI_FEATURE_RW_NDEF)

/**
 * @brief 写入T2T数据（1 block=4 byte）
 *
 * @param bl_addr 写入起始地址block编号
 * @param p_dat 要写入的数据指针，必须有4个字节
 * @param pp_rsp 返回的响应数据
 *
 * @return 成功返回NCI_STATUS_OK, 失败返回其他错误码
 */
static tNCI_STATUS t2t_write_block(uint16_t bl_addr, const uint8_t *p_dat, tNCI_BUF **pp_rsp) {
    tNCI_BUF *cmd = alloc_nci_buf_with_cap(0, T2T_CMD_LEN_READ);
    tNCI_BUF *rsp = *pp_rsp;
    tNCI_STATUS ret = NCI_STATUS_EXT_FAILED;
    if (!rsp) {
        rsp = alloc_nci_buf_with_cap(0, T2T_RSP_LEN_READ);
    } else {
        reset_nci_buf(rsp);
    }
    if (!cmd || !rsp) {
        NFCLOG_E("alloc_nci_buf failed");
        ret = NCI_STATUS_EXT_ALLOC_FAILED;
        goto failed;
    }

    tT2T_INFO *p_t2t = &s_t2t_info;
    uint8_t blno = bl_addr % T2T_BLOCKS_PRE_SECTOR;
    uint8_t sec_no = bl_addr / T2T_BLOCKS_PRE_SECTOR;

    if (sec_no != p_t2t->curr_sec_no) {
        // 当前sector和目标sector不一致，需要先切换到目标sector
        ret = t2t_sector_select(sec_no, &rsp);
        if (ret != NCI_STATUS_OK) {
            NFCLOG_E("t2t_sector_select failed, ret=%d", ret);
            goto failed;
        }
    }

    UINT8_TO_BUF(cmd, T2T_CMD_WRITE);
    UINT8_TO_BUF(cmd, blno);
    ARRAY_TO_BUF(cmd, p_dat, T2T_BYTES_PRE_BLOCK);
    s_t2t_info.skip_check_nak = true;
    uint8_t retry_count = 0;
    do {
        ret = rw_transmit(cmd, rsp);
        s_t2t_info.skip_check_nak = false;
        if (ret != NCI_STATUS_OK) {
            NFCLOG_E("rw_transmit failed, ret=%d", ret);
            goto failed;
        }
        if (rsp->len != T2T_RSP_LEN_WRITE) {
            ret = NCI_STATUS_EXT_FAILED;
            NFCLOG_E("write block failed, len=%d", rsp->len);
            goto failed;
        }
        if ((rsp->data[0] & 0x0F) != T2T_ACK) {
            NFCLOG_W("write block failed, nak=0x%02X, retry once", rsp->data[0]);
            continue;
        }
        break;
    } while (retry_count++ < 1);
    *pp_rsp = rsp;
    goto cleanup;
failed:
    free_nci_buf(rsp);
    *pp_rsp = NULL;
cleanup:
    free_nci_buf(cmd);
    return ret;
}
/**
 * @brief 选择T2T的扇区
 *
 * @param sec_no 扇区号
 *
 * @return 成功返回NCI_STATUS_OK，失败返回其他错误码
 */
tNCI_STATUS nfa_rw_t2t_sector_select(uint8_t sec_no) {
    tNCI_STATUS ret = nfa_rw_request_lock();
    if (ret != NCI_STATUS_OK) {
        NFCLOG_E("nfa_rw_request_lock failed, ret=%d", ret);
        return ret;
    }
    tNCI_BUF *rsp = NULL;
    ret = t2t_sector_select(sec_no, &rsp);
    free_nci_buf(rsp);
    nfa_rw_release_lock();
    return ret;
}
/**
 * @brief 读取一页T2T数据（16字节）
 *
 * @param[in] block_no 起始块号
 * @param[out] p_rsp 返回的数据
 *
 * @note 当返回NCI_STATUS_OK时，p_rsp才有效，需要调用nfa_utils_free_rsp释放
 *
 * @return 成功返回NCI_STATUS_OK，失败返回其他错误码
 */
tNCI_STATUS nfa_rw_t2t_read_page(uint8_t block_no, tNCI_RSP *p_rsp) {
    tNCI_STATUS ret = nfa_rw_request_lock();
    if (ret != NCI_STATUS_OK) {
        NFCLOG_E("nfa_rw_request_lock failed, ret=%d", ret);
        return ret;
    }
    tNCI_BUF *rsp = NULL;
    ret = t2t_read_page(block_no, &rsp);
    if (ret != NCI_STATUS_OK) {
        NFCLOG_E("t2t_read_page failed, ret=%d", ret);
        goto cleanup;
    }
    // 交换rsp->data到p_rsp->data，减少一次内存开辟和拷贝
    p_rsp->data = rsp->data;
    rsp->data = NULL;
    p_rsp->len = rsp->len;
cleanup:
    nfa_rw_release_lock();
    free_nci_buf(rsp);
    return ret;
}
/**
 * @brief 写入一Block T2T数据（4字节）
 *
 * @param block_no 写入的块号
 * @param p_data 写入的数据，必须至少有4个字节
 *
 * @return 成功返回NCI_STATUS_OK，失败返回其他错误码
 */
tNCI_STATUS nfa_rw_t2t_write_block(uint8_t block_no, const uint8_t *p_data) {
    tNCI_STATUS ret = nfa_rw_request_lock();
    if (ret != NCI_STATUS_OK) {
        NFCLOG_E("nfa_rw_request_lock failed, ret=%d", ret);
        return ret;
    }
    tNCI_BUF *rsp = NULL;
    ret = t2t_write_block(block_no, p_data, &rsp);
    if (ret != NCI_STATUS_OK) {
        NFCLOG_E("t2t_write_block failed, ret=%d", ret);
    }
    nfa_rw_release_lock();
    free_nci_buf(rsp);
    return ret;
}

static void dump_t2t_info() {
    NFCLOG_I("=========== T2T Info Start==========");
    NFCLOG_I("is_ndef_detected=%d", s_t2t_info.is_ndef_detected);
    NFCLOG_I("is_static_locked=%d", s_t2t_info.is_static_locked);
    NFCLOG_I("curr_sec_no=%d", s_t2t_info.curr_sec_no);

    NFCLOG_I("attr_len=%d", s_t2t_info.attr_len);
    char *attr_str = osi_calloc(s_t2t_info.attr_len * 2 + 1);
    bytes_to_hex(s_t2t_info.attr, s_t2t_info.attr_len, attr_str);
    NFCLOG_I("attr=%s", attr_str);
    NFCLOG_I("lock_attr_len=%d", s_t2t_info.lock_attr_len);
    bytes_to_hex(s_t2t_info.lock_attr, s_t2t_info.lock_attr_len, attr_str);
    NFCLOG_I("lock_attr=%s", attr_str);

    NFCLOG_I("ndef_len_start=%d", s_t2t_info.ndef_len_start);
    NFCLOG_I("ndef_value_start=%d", s_t2t_info.ndef_value_start);
    NFCLOG_I("ndef_value_len=%d", s_t2t_info.ndef_value_len);
    NFCLOG_I("ndef_max_size=%d", s_t2t_info.ndef_max_size);
    NFCLOG_I("ndef_flags=0x%02X", s_t2t_info.ndef_flags);
    bytes_to_hex(s_t2t_info.ndef_first_block, T2T_BYTES_PRE_BLOCK, attr_str);
    NFCLOG_I("ndef_first_block=%s", attr_str);
    NFCLOG_I("=========== T2T Info End============");

    osi_free(attr_str);
}

static tNCI_STATUS init_attr() {
    tT2T_INFO *p_t2t = &s_t2t_info;

    uint16_t t2t_area_size = p_t2t->hdr[T2T_CC2_TMS_BYTE] << 3;

    p_t2t->attr_len = p_t2t->max_size >> 3;
    p_t2t->attr = osi_calloc(p_t2t->attr_len);
    if (!p_t2t->attr) {
        NFCLOG_E("alloc attr failed");
        return NCI_STATUS_EXT_ALLOC_FAILED;
    }
    // 前3个block都是保留区域
    p_t2t->attr[0] = 0xFF;
    p_t2t->attr[1] = 0x0F;

    p_t2t->lock_attr_len = 0;
    if (t2t_area_size > T2T_AREA_STATIC_SIZE) {
        // 支持动态内存空间
        p_t2t->lock_attr_len = (t2t_area_size - T2T_AREA_STATIC_SIZE) >> 3;
        p_t2t->lock_attr = osi_calloc(p_t2t->lock_attr_len);
        if (!p_t2t->lock_attr) {
            NFCLOG_E("alloc lock attr failed");
            return NCI_STATUS_EXT_ALLOC_FAILED;
        }
    }
    return NCI_STATUS_OK;
}

static void set_revd_attr(uint16_t addr, uint16_t len) {
    tT2T_INFO *p_t2t = &s_t2t_info;
    uint16_t end_addr = addr + len;
    if (end_addr % T2T_BYTES_PRE_BLOCK) {
        // 如果不是整个block，需要补齐到整个block
        end_addr = ((end_addr / T2T_BYTES_PRE_BLOCK) + 1) * T2T_BYTES_PRE_BLOCK;
    }
    for (uint16_t i = addr; i < end_addr; i++) {
        uint16_t attr_offset = i / T2T_BYTES_PRE_ATTR_BYTE_CTRL;
        if (attr_offset > p_t2t->attr_len) {
            NFCLOG_E("attr offset out of range");
            return;
        }
        uint8_t attr_bit = i % T2T_BYTES_PRE_ATTR_BYTE_CTRL;
        p_t2t->attr[attr_offset] |= (1 << attr_bit);
    }
}

static tNCI_STATUS set_lock_attr(uint16_t start_addr, uint8_t num_lock_bits, uint8_t bytes_locked_pre_lock_bit) {
    tT2T_INFO *p_t2t = &s_t2t_info;
    p_t2t->lock_bits_start = start_addr;
    p_t2t->lock_bits_count = num_lock_bits;
    uint8_t num_lock_bytes = num_lock_bits / BITS_PER_BYTE;
    if (num_lock_bits % BITS_PER_BYTE) {
        num_lock_bytes++;
    }

    uint8_t offset_in_block = start_addr % T2T_BYTES_PRE_BLOCK;
    tNCI_BUF *rsp = NULL;
    tNCI_STATUS ret = NCI_STATUS_FAILED;
    uint8_t read_lock_byte_size = 0;
    uint16_t dynamic_offset = 0;
    while (read_lock_byte_size < num_lock_bytes) {
        uint16_t bl_addr = (start_addr + read_lock_byte_size) / T2T_BYTES_PRE_BLOCK;
        NFCLOG_I("set_lock_attr bl_addr=%d, read_lock_byte_size=%d, num_lock_bytes=%d, offset_in_block=%d, dynamic_offset=%d", bl_addr, read_lock_byte_size, num_lock_bytes, offset_in_block, dynamic_offset);
        ret = t2t_read_page(bl_addr, &rsp);
        if (ret != NCI_STATUS_OK) {
            NFCLOG_E("t2t_read_page(%d) failed, ret=%d", bl_addr, ret);
            goto cleanup;
        }

        uint8_t *p_lock_bytes = rsp->data + offset_in_block;
        uint8_t remain_lock_bytes = num_lock_bytes - read_lock_byte_size;
        for (uint8_t i = 0; i < remain_lock_bytes; i++) {
            uint8_t num_of_bits = BITS_PER_BYTE;
            if (i == (remain_lock_bytes - 1)) {
                num_of_bits = ((num_lock_bits % BITS_PER_BYTE) == 0) ? BITS_PER_BYTE : (num_lock_bits % BITS_PER_BYTE);
            }

            for (uint8_t j = 0; j < num_of_bits; j++) {
                if (p_lock_bytes[i] & s_t2t_mask_bits[j]) {
                    // 当前bit是锁定状态，更新lock_attr
                    for (uint8_t k = 0; k < bytes_locked_pre_lock_bit; k++) {
                        uint16_t curr_offset = dynamic_offset + k;
                        uint16_t lock_attr_index = curr_offset / T2T_BYTES_PRE_ATTR_BYTE_CTRL;
                        if (lock_attr_index > p_t2t->lock_attr_len) {
                            // lock attr index超出范围，卡片实际拥有的容量小于lock bits可以控制的容量，后续的部分不再处理
                            NFCLOG_E("lock attr index out of range, index=%d, len=%d", lock_attr_index, p_t2t->lock_attr_len);
                            goto cleanup;
                        }
                        p_t2t->lock_attr[lock_attr_index] |= 0x01 << (curr_offset % T2T_BYTES_PRE_ATTR_BYTE_CTRL);
                    }
                }
                dynamic_offset += bytes_locked_pre_lock_bit;
            }
        }
        offset_in_block = 0;
        read_lock_byte_size += T2T_BYTES_PRE_PAGE;
    }

    ret = NCI_STATUS_OK;
cleanup:
    free_nci_buf(rsp);
    return ret;
}

static bool is_revd_byte(uint16_t offset) {
    uint16_t attr_offset = offset / T2T_BYTES_PRE_ATTR_BYTE_CTRL;
    if (attr_offset > s_t2t_info.attr_len) {
        NFCLOG_E("attr offset out of range, offset=%d, len=%d", attr_offset, s_t2t_info.attr_len);
        return true;
    }
    uint8_t attr_bit = offset % T2T_BYTES_PRE_ATTR_BYTE_CTRL;
    return s_t2t_info.attr[attr_offset] & s_t2t_mask_bits[attr_bit];
}

static bool is_read_only_byte(uint16_t offset) {
    if (offset < T2T_BYTES_PRE_PAGE) {
        return true;
    } else if (offset < T2T_STATIC_SIZE) {
        // 静态内存区域
        return s_t2t_info.is_static_locked;
    }
    uint16_t dynamic_area_offset = offset - T2T_STATIC_SIZE;
    uint16_t lock_attr_offset = dynamic_area_offset / T2T_BYTES_PRE_ATTR_BYTE_CTRL;
    if (lock_attr_offset >= s_t2t_info.lock_attr_len) {
        NFCLOG_E("lock attr offset out of range, offset=%d, len=%d", lock_attr_offset, s_t2t_info.lock_attr_len);
        return true;
    }
    uint8_t lock_attr_bit = dynamic_area_offset % T2T_BYTES_PRE_ATTR_BYTE_CTRL;
    return s_t2t_info.lock_attr[lock_attr_offset] & s_t2t_mask_bits[lock_attr_bit];
}

#define T2T_STATE_FIND_TAG           0
#define T2T_STATE_FIND_LEN           1
#define T2T_STATE_FIND_EXT_LEN_START 2
#define T2T_STATE_FIND_EXT_LEN_END   3
#define T2T_STATE_FIND_VALUE         4

static tNCI_STATUS scan_t2t_data() {
    tT2T_INFO *p_t2t = &s_t2t_info;
    if (p_t2t->is_ndef_detected) {
        return NCI_STATUS_OK;
    }

    tNCI_BUF *rsp = NULL;
    tNCI_STATUS ret = t2t_read_page(0, &rsp);
    if (ret != NCI_STATUS_OK) {
        goto cleanup;
    }

    if (!osi_memcpy_s(p_t2t->hdr, T2T_BYTES_PRE_PAGE, rsp->data, rsp->len)) {
        NFCLOG_E("copy memory failed");
        ret = NCI_STATUS_EXT_COPY_FAILED;
        goto cleanup;
    }
    p_t2t->max_size = (p_t2t->hdr[T2T_CC2_TMS_BYTE] << 3) + T2T_HDR_SIZE;
    if (p_t2t->hdr[T2T_STATIC_LOCK0_BYTE] == T2T_STATIC_LOCK_READ_ONLY && p_t2t->hdr[T2T_STATIC_LOCK1_BYTE] == T2T_STATIC_LOCK_READ_ONLY) {
        p_t2t->is_static_locked = true;
    }

    if (p_t2t->hdr[T2T_CC0_NMN_BYTE] != T2T_CC0_NMN) {
        NFCLOG_E("not support ndef, nmn=0x%02X", p_t2t->hdr[T2T_CC0_NMN_BYTE]);
        ret = NCI_STATUS_OK;
        goto cleanup;
    }
    if (init_attr() != NCI_STATUS_OK) {
        NFCLOG_E("init attr failed");
        ret = NCI_STATUS_EXT_FAILED;
        goto cleanup;
    }
    uint16_t t2t_area_size = (p_t2t->hdr[T2T_CC2_TMS_BYTE]) << 3;
    uint16_t t2t_area_with_hdr_size = t2t_area_size + T2T_BYTES_PRE_PAGE;
    uint8_t curr_state = T2T_STATE_FIND_TAG;
    uint16_t byte_offset = T2T_BYTES_PRE_PAGE;
    uint8_t curr_tag = 0;
    uint16_t curr_len = 0;
    uint8_t value_buf[3] = {};
    uint8_t value_buf_len = 0;
    bool is_found_lock_tlv = false;

    uint8_t cc1 = p_t2t->hdr[T2T_CC1_VNO_BYTE];
    uint8_t cc3 = p_t2t->hdr[T2T_CC3_RWA_BYTE];
    if ((cc3 != T2T_CC3_RWA_RW && cc3 != T2T_CC3_RWA_RO) ||
        (cc1 != T2T_CC1_VNO && cc1 != T2T_CC1_VNO_LEGACY && cc1 != T2T_CC1_VNO_NEW)) {
        NFCLOG_E("invalid version number or rwa byte, vno=0x%02X, rwa=0x%02X", cc1, cc3);
        ret = NCI_STATUS_FAILED;
        goto cleanup;
    }

    while (byte_offset < t2t_area_with_hdr_size) {
        uint16_t curr_block_address = byte_offset / T2T_BYTES_PRE_BLOCK;
        ret = t2t_read_page(curr_block_address, &rsp);
        if (ret != NCI_STATUS_OK) {
            NFCLOG_E("t2t_read_page(%d) failed, ret=%d", curr_block_address, ret);
            goto cleanup;
        }
        for (uint8_t i = 0; i < T2T_BYTES_PRE_PAGE; ++i) {
            uint8_t byte = rsp->data[i];
            if (is_revd_byte(byte_offset + i)) {
                continue;
            }
            switch (curr_state) {
                case T2T_STATE_FIND_TAG:
                    // 记录TAG
                    value_buf_len = 0;
                    osi_memset_s(value_buf, sizeof(value_buf), 0, sizeof(value_buf));
                    curr_tag = byte;
                    if (curr_tag == T2T_TLV_NULL) {
                        continue;
                    } else if (curr_tag == T2T_TLV_TERM) {
                        goto tlv_detect_done;
                    }
                    curr_state = T2T_STATE_FIND_LEN;
                    break;
                case T2T_STATE_FIND_LEN:
                    // 记录LEN
                    if (curr_tag == T2T_TLV_NDEF) {
                        // 记录NDEF LEN起始位置
                        p_t2t->ndef_len_start = byte_offset + i;
                        uint8_t page_offset = (i / T2T_BYTES_PRE_BLOCK) * T2T_BYTES_PRE_BLOCK;
                        if (!osi_memcpy_s(p_t2t->ndef_first_block, T2T_BYTES_PRE_BLOCK, rsp->data + page_offset, T2T_BYTES_PRE_BLOCK)) {
                            NFCLOG_E("copy memory failed");
                            ret = NCI_STATUS_EXT_COPY_FAILED;
                            goto cleanup;
                        }
                    }
                    curr_len = byte;
                    if (curr_len == 0xFF) {
                        // 是扩展长度，需要再读取两个字节
                        curr_state = T2T_STATE_FIND_EXT_LEN_START;
                    } else {
                        curr_state = T2T_STATE_FIND_VALUE;
                    }
                    break;
                case T2T_STATE_FIND_EXT_LEN_START:
                    // 记录扩展长度第一个字节
                    curr_len = (byte << 8);
                    curr_state = T2T_STATE_FIND_EXT_LEN_END;
                    break;
                case T2T_STATE_FIND_EXT_LEN_END:
                    // 记录扩展长度第二个字节
                    curr_len |= byte;
                    curr_state = T2T_STATE_FIND_VALUE;
                    break;
                case T2T_STATE_FIND_VALUE:
                    // 记录Value
                    if (curr_tag == T2T_TLV_NDEF) {
                        // 找到NDEF, 跳出循环
                        p_t2t->ndef_value_start = byte_offset + i;
                        p_t2t->ndef_value_len = curr_len;
                        goto tlv_detect_done;
                    }
                    if (value_buf_len < curr_len) {
                        if (value_buf_len < sizeof(value_buf)) {
                            value_buf[value_buf_len] = byte;
                        }
                        value_buf_len++;
                    }
                    if (value_buf_len < curr_len) {
                        // Value还未读完, 继续查找下一个Value
                        continue;
                    }
                    // Value读完, 开始处理
                    if (curr_tag == T2T_TLV_LOCK) {
                        is_found_lock_tlv = true;
                        uint8_t nbr_major_offsets = value_buf[0] >> 4;
                        uint8_t nbr_minor_offsets = value_buf[0] & 0x0F;
                        uint8_t dla_nbr_lock_bits = value_buf[1];
                        uint8_t blplb_index = value_buf[2] >> 4;
                        uint8_t mos_dla = value_buf[2] & 0x0F;

                        uint8_t bytes_locked_pre_lock_bit = 1 << blplb_index;
                        uint16_t dynamic_lock_area_first_byte_addr = (nbr_major_offsets << mos_dla) + nbr_minor_offsets;
                        uint8_t dynamic_lock_area_nbr_bytes = dla_nbr_lock_bits / 8;
                        if (dla_nbr_lock_bits % 8 != 0) {
                            dynamic_lock_area_nbr_bytes++;
                        }

                        NFCLOG_I("dynamic_lock_area_first_byte_addr=%d, dynamic_lock_area_nbr_bytes=%d", dynamic_lock_area_first_byte_addr, dynamic_lock_area_nbr_bytes);
                        set_revd_attr(dynamic_lock_area_first_byte_addr, dynamic_lock_area_nbr_bytes);
                        tNCI_STATUS set_lock_attr_ret = set_lock_attr(dynamic_lock_area_first_byte_addr, dla_nbr_lock_bits, bytes_locked_pre_lock_bit);
                        if (set_lock_attr_ret != NCI_STATUS_OK) {
                            NFCLOG_E("set_lock_attr failed, ret=%d", set_lock_attr_ret);
                            ret = rw_re_select();
                            if (ret != NCI_STATUS_OK) {
                                NFCLOG_E("rw_re_select failed, ret=%d", ret);
                                goto cleanup;
                            }
                        }
                    } else if (curr_tag == T2T_TLV_MEM) {
                        uint8_t nbr_major_offsets = value_buf[0] >> 4;
                        uint8_t nbr_minor_offsets = value_buf[0] & 0x0F;
                        uint8_t rsvd_area_size = value_buf[1];
                        uint8_t mos_ra = value_buf[2] & 0x0F;

                        uint16_t rsvd_area_first_byte_addr = (nbr_major_offsets << mos_ra) + nbr_minor_offsets;

                        NFCLOG_I("rsvd_area_first_byte_addr=%d, rsvd_area_size=%d", rsvd_area_first_byte_addr, rsvd_area_size);
                        set_revd_attr(rsvd_area_first_byte_addr, rsvd_area_size);
                    }
                    curr_state = T2T_STATE_FIND_TAG;
                    break;
                default:
                    NFCLOG_E("Invalid state %d", curr_state);
                    ret = NCI_STATUS_EXT_FAILED;
                    goto cleanup;
            }
        }
        byte_offset += T2T_BYTES_PRE_PAGE;
    }
tlv_detect_done:
    if (!is_found_lock_tlv && t2t_area_size > T2T_AREA_STATIC_SIZE) {
        NFCLOG_I("No Lock TLV found, use default setting");
        uint16_t dynamic_area_size = t2t_area_size - T2T_AREA_STATIC_SIZE;
        uint8_t bytes_locked_pre_lock_bit = 8;
        if (p_t2t->hdr[0] == T2T_TAG_KOVIO_MID) {
            bytes_locked_pre_lock_bit = 4;
        }
        uint8_t nbr_of_dynamic_lock_bits = dynamic_area_size / bytes_locked_pre_lock_bit;
        if (dynamic_area_size % bytes_locked_pre_lock_bit != 0) {
            nbr_of_dynamic_lock_bits++;
        }
        tNCI_STATUS set_lock_attr_ret = set_lock_attr(t2t_area_size + T2T_HDR_SIZE, nbr_of_dynamic_lock_bits, bytes_locked_pre_lock_bit);
        if (set_lock_attr_ret != NCI_STATUS_OK) {
            NFCLOG_E("set_lock_attr failed, ret=%d", set_lock_attr_ret);
        }
    }

    uint16_t ndef_max_size = 0;
    if (p_t2t->ndef_len_start > 0) {
        NFCLOG_I("NDEF length start=%d, t2t_area_with_hdr_size=%d", p_t2t->ndef_len_start, t2t_area_with_hdr_size);
        byte_offset = p_t2t->ndef_len_start;
        while (byte_offset < t2t_area_with_hdr_size) {
            if (!is_revd_byte(byte_offset)) {
                if (is_read_only_byte(byte_offset)) {
                    break;
                }
                ndef_max_size++;
            } else {
                NFCLOG_I("byte_offset=%d is revd byte", byte_offset);
            }
            byte_offset++;
        }
    } else {
        ndef_max_size = t2t_area_size - 1; // 减去NDEF TAG一字节
    }
    if (ndef_max_size > 0xFF) {
        ndef_max_size -= 3;
    } else if (ndef_max_size > 0) {
        ndef_max_size -= 1;
    }
    p_t2t->ndef_max_size = ndef_max_size;

    if (cc3 == T2T_CC3_RWA_RO) {
        p_t2t->ndef_max_size = p_t2t->ndef_value_len;
    }

    uint8_t ndef_flags = 0;
    ndef_flags |= NCI_RW_NDEF_FL_SUPPORTED;
    ndef_flags |= NCI_RW_NDEF_FL_FORMATABLE;
    if ((p_t2t->hdr[T2T_CC3_RWA_BYTE] & T2T_CC3_RWA_RO) == T2T_CC3_RWA_RO) {
        ndef_flags |= NCI_RW_NDEF_FL_READ_ONLY;
    }
    if (p_t2t->ndef_max_size < p_t2t->ndef_value_len) {
        ndef_flags |= NCI_RW_NDEF_FL_READ_ONLY;
        p_t2t->ndef_max_size = p_t2t->ndef_value_len;
    }

    p_t2t->ndef_flags = ndef_flags;

    dump_t2t_info();

cleanup:
    if (ret != NCI_STATUS_OK) {
        reset_t2t_info();
    } else {
        p_t2t->is_ndef_detected = true;
    }
    free_nci_buf(rsp);
    return ret;
}

static tT2T_INIT_TAG *find_tag_init_data(uint8_t manufacturer_id, bool check_version, uint16_t version_no) {
    for (uint8_t i = 0; i < T2T_INIT_TAGS_SIZE; i++) {
        tT2T_INIT_TAG *p_init = &s_t2t_init_tags[i];
        if (manufacturer_id == p_init->manufacturer_id) {
            if (!p_init->is_multi_version || !check_version || p_init->version_no == version_no) {
                return p_init;
            }
        }
    }
    return NULL;
}

static tNCI_STATUS ndef_detect(tNCI_RW_NDEF_INFO *p_ndef) {
    reset_t2t_info();
    tNCI_STATUS ret = scan_t2t_data();
    if (ret != NCI_STATUS_OK) {
        goto cleanup;
    }

    tT2T_INFO *p_t2t = &s_t2t_info;

    if (p_t2t->hdr[T2T_CC0_NMN_BYTE] != T2T_CC0_NMN) {
        ret = NCI_STATUS_EXT_NOT_SUPPORTED;
        goto cleanup;
    }

    p_ndef->curr_size = p_t2t->ndef_value_len;
    p_ndef->max_size = p_t2t->ndef_max_size;
    if (p_t2t->ndef_flags & NCI_RW_NDEF_FL_READ_ONLY) {
        p_ndef->mode = NCI_RW_NDEF_MODE_READ_ONLY;
    } else {
        p_ndef->mode = NCI_RW_NDEF_MODE_READ_WRITE;
    }
    ret = NCI_STATUS_OK;

cleanup:
    return ret;
}

static tNCI_STATUS ndef_read(tNCI_RSP *p_rsp) {
    tT2T_INFO *p_t2t = &s_t2t_info;
    tNCI_BUF *rsp = NULL;
    tNCI_STATUS ret = NCI_STATUS_EXT_FAILED;
    if (!p_t2t->is_ndef_detected) {
        NFCLOG_E("ndef not detected");
        return NCI_STATUS_EXT_FAILED;
    }
    if (p_t2t->ndef_value_start == 0) {
        NFCLOG_E("no ndef message found");
        return NCI_STATUS_EXT_FAILED;
    }
    if (p_t2t->ndef_value_len == 0) {
        p_rsp->len = 0;
        NFCLOG_I("empty ndef message");
        return NCI_STATUS_EXT_EMPTY_DATA;
    }

    p_rsp->data = osi_calloc(p_t2t->ndef_value_len);
    if (!p_rsp->data) {
        NFCLOG_E("failed to allocate memory for ndef message");
        ret = NCI_STATUS_EXT_ALLOC_FAILED;
        goto cleanup;
    }
    uint16_t byte_offset = p_t2t->ndef_value_start;

    while (byte_offset < p_t2t->max_size && p_rsp->len < p_t2t->ndef_value_len) {
        // 每一轮循环都读取一个page的数据，然后填充到p_rsp->data中
        // 按page对齐读取数据
        uint16_t bl_addr = (byte_offset / T2T_BYTES_PRE_PAGE) * T2T_BLOCKS_PRE_PAGE;
        ret = t2t_read_page(bl_addr, &rsp);
        if (ret != NCI_STATUS_OK) {
            goto cleanup;
        }
        uint16_t page_start_offset = bl_addr * T2T_BYTES_PRE_BLOCK;
        uint8_t offset_in_page = byte_offset % T2T_BYTES_PRE_PAGE;

        byte_offset = (bl_addr + T2T_BLOCKS_PRE_PAGE) * T2T_BYTES_PRE_BLOCK; // byte_offset指向下一个page的第一个byte
        // 将page中非revd的byte填充到p_rsp->data中
        for (uint8_t i = offset_in_page; i < T2T_BYTES_PRE_PAGE && p_rsp->len < p_t2t->ndef_value_len; ++i) {
            if (!is_revd_byte(page_start_offset + i)) {
                p_rsp->data[p_rsp->len++] = rsp->data[i];
            }
        }
    }

    if (p_rsp->len != p_t2t->ndef_value_len) {
        NFCLOG_E("read ndef message failed, read %d bytes", p_rsp->len);
        ret = NCI_STATUS_EXT_FAILED;
        goto cleanup;
    }

    ret = NCI_STATUS_OK;
cleanup:
    free_nci_buf(rsp);
    if (ret != NCI_STATUS_OK) {
        if (p_rsp->data) {
            osi_free(p_rsp->data);
            p_rsp->data = NULL;
        }
        p_rsp->len = 0;
    }
    return ret;
}

static tNCI_STATUS ndef_format() {
    tNCI_STATUS ret = scan_t2t_data();
    tNCI_BUF *rsp = NULL;
    if (ret != NCI_STATUS_OK) {
        NFCLOG_E("scan_t2t_data failed, ret=%d", ret);
        goto cleanup;
    }
    tT2T_INFO *p_t2t = &s_t2t_info;
    uint8_t manufacturer_id = p_t2t->hdr[0];

    // 先通过manufacturer_id判断是否支持
    tT2T_INIT_TAG *p_init = find_tag_init_data(manufacturer_id, false, 0);
    if (!p_init) {
        NFCLOG_E("manufacturer_id=0x%02X not supported", manufacturer_id);
        ret = NCI_STATUS_EXT_NOT_SUPPORTED;
        goto cleanup;
    }

    bool is_blank_tag = true;
    uint8_t ndef_magic_number = p_t2t->hdr[T2T_CC0_NMN_BYTE];
    uint8_t cc_version_no = p_t2t->hdr[T2T_CC1_VNO_BYTE];
    uint8_t t2t_area_size = p_t2t->hdr[T2T_CC2_TMS_BYTE];
    uint8_t tms = p_init->tms;

    if (t2t_area_size != 0) {
        // 当前TMS字段不为0，表示卡片可能已经格式化过了，需要进一步判断
        if ((p_t2t->ndef_value_len > 0) && p_init->is_opt) {
            NFCLOG_E("Cannot format a OTP tag with NDEF Message!");
            return NCI_STATUS_EXT_FAILED;
        }

        if (((ndef_magic_number != 0) && (ndef_magic_number != T2T_CC0_NMN)) ||
            ((cc_version_no != 0) && (cc_version_no != T2T_CC1_VNO) && (cc_version_no != T2T_CC1_VNO_LEGACY) && (cc_version_no != T2T_CC1_VNO_NEW))) {
            NFCLOG_E("Tag not blank to format!");
            return NCI_STATUS_EXT_FAILED;
        } else {
            is_blank_tag = false;
            tms = t2t_area_size;
        }
    }
    uint8_t lock_bit_num = 0;
    uint16_t lock_addr = 0;
    uint16_t locked_area_size = 0;

    if (is_blank_tag && p_init->is_multi_version) {
        // 此tag支持多版本，需要进一步判断版本号
        uint8_t *p_version_data = p_t2t->hdr;
        if (p_init->version_block != 0) {
            // 版本信息不在第一个block，需要读取对应位置的数据
            ret = t2t_read_page(p_init->version_block, &rsp);
            if (ret != NCI_STATUS_OK) {
                NFCLOG_E("read version block failed, ret=%d", ret);
                goto cleanup;
            }
            p_version_data = rsp->data;
        }
        uint16_t version_no = ((p_version_data[0] << 8) | p_version_data[1]) & p_init->version_mask;
        p_init = find_tag_init_data(manufacturer_id, true, version_no);
        if (p_init) {
            if (p_init->calc_cc) {
                // 需要进一步计算TMS
                uint16_t l_chunk_size = (uint16_t)p_version_data[2] << 8 | p_version_data[3];
                uint16_t num_l_chuncks = (uint16_t)p_version_data[4] << 8 | p_version_data[5];

                uint16_t size = (uint16_t) (l_chunk_size * num_l_chuncks);

                lock_addr = size + T2T_STATIC_SIZE;
                locked_area_size = l_chunk_size * ((uint16_t) p_version_data[6]);
                lock_bit_num = p_version_data[7];

                size += (T2T_STATIC_SIZE - T2T_HDR_SIZE);
                tms = size / 0x08;
            } else {
                tms = p_init->tms;
            }
        }
    } else {
        NFCLOG_I("Current tag is not blank or not multi-version tag, just set empty ndef tlv");
    }

    uint8_t tag_data[T2T_BYTES_PRE_PAGE] = {};
    tag_data[0] = T2T_CC0_NMN;
    tag_data[1] = T2T_CC1_VNO;
    tag_data[2] = tms;
    tag_data[3] = T2T_CC3_RWA_RW;

    ret = t2t_write_block(T2T_CC_BLOCK_NO, tag_data, &rsp);
    if (ret != NCI_STATUS_OK) {
        NFCLOG_E("write CC block failed, ret=%d", ret);
        goto cleanup;
    }

    if (!osi_memset_s(tag_data, T2T_BYTES_PRE_PAGE, 0x00, T2T_BYTES_PRE_PAGE)) {
        ret = NCI_STATUS_EXT_FAILED;
        NFCLOG_E("memset failed");
        goto cleanup;
    }

    uint8_t data_len = 0;

    // 需要设置LOCK TLV的情况
    if (tms > T2T_CC2_TMS_STATIC && p_init && p_init->calc_cc) {
        uint8_t mos_dla = (uint8_t)rw_utils_tags_log2(locked_area_size);
        uint8_t blplb = p_init->bytes_locked_pre_lock_bit;
        int8_t nbr_major_offsets = 0;
        int8_t nbr_minor_offsets = 0;
        for (nbr_major_offsets = 0xF; nbr_major_offsets > 0; nbr_major_offsets--) {
            nbr_minor_offsets = (int8_t)(lock_addr - (nbr_major_offsets << mos_dla));
            if (nbr_minor_offsets >= 0 && nbr_minor_offsets < 0x10) {
                break;
            }
        }

        uint8_t lock_byte1 = ((nbr_major_offsets & 0x0F) << 4) | (nbr_minor_offsets & 0x0F);
        uint8_t lock_byte2 = lock_bit_num;
        uint8_t lock_byte3 = (blplb << 4) | mos_dla;

        tag_data[data_len++] = T2T_TLV_LOCK;
        tag_data[data_len++] = T2T_TLV_LEN_LOCK;
        tag_data[data_len++] = lock_byte1;
        tag_data[data_len++] = lock_byte2;
        tag_data[data_len++] = lock_byte3;
    }

    // 设置NDEF TLV
    tag_data[data_len++] = T2T_TLV_NDEF;
    tag_data[data_len++] = 0;
    if (p_init && !p_init->is_opt) {
        tag_data[data_len++] = T2T_TLV_TERM;
    }

    // 写入数据
    uint8_t write_len = 0;
    uint8_t block_no = T2T_AREA_FIRST_BLOCK_NO;
    while (write_len < data_len) {
        ret = t2t_write_block(block_no, tag_data + write_len, &rsp);
        if (ret != NCI_STATUS_OK) {
            NFCLOG_E("write block failed, ret=%d", ret);
            goto cleanup;
        }
        write_len += T2T_BYTES_PRE_BLOCK;
        block_no++;
    }

    // p_t2t->ndef_value_len = 0;
    // p_t2t->ndef_len_start = ndef_len_start;
    // p_t2t->ndef_value_start = ndef_len_start + 1;

    ret = NCI_STATUS_OK;
cleanup:
    reset_t2t_info();
    if (ret == NCI_STATUS_OK) {
        ret = scan_t2t_data();
    }
    free_nci_buf(rsp);
    return ret;
}

static tNCI_STATUS ndef_Write_update_ndef_len(uint16_t new_ndef_len, tNCI_BUF *p_rsp) {
    tNCI_STATUS ret = NCI_STATUS_EXT_FAILED;
    tT2T_INFO *p_t2t = &s_t2t_info;
    uint8_t ndef_len_block = p_t2t->ndef_len_start / T2T_BYTES_PRE_BLOCK;
    uint8_t ndef_len_offset_in_block = p_t2t->ndef_len_start % T2T_BYTES_PRE_BLOCK;

    uint8_t ndef_length_array[3] = {0};
    uint8_t write_buf[T2T_BYTES_PRE_BLOCK] = {0};
    uint8_t ndef_len_len = 1;
    if (new_ndef_len > 0xFF) {
        ndef_len_len = 3;
        ndef_length_array[0] = 0xFF;
        ndef_length_array[1] = new_ndef_len >> 8;
        ndef_length_array[2] = (uint8_t)(new_ndef_len & 0xFF);
    } else {
        ndef_length_array[0] = (uint8_t)(new_ndef_len & 0xFF);
    }
    uint8_t write_len = 0;
    uint8_t curr_block = ndef_len_block;
    while (write_len < ndef_len_len) {
        if (write_len == 0) {
            // 第一个block直接使用之前保存的
            if (!osi_memcpy_s(write_buf, sizeof(write_buf), p_t2t->ndef_first_block, T2T_BYTES_PRE_BLOCK)) {
                NFCLOG_E("memcpy failed");
                return NCI_STATUS_EXT_COPY_FAILED;
            }
        } else {
            // 第二个block需要读取
            ret = t2t_read_page(curr_block, &p_rsp);
            if (ret != NCI_STATUS_OK) {
                NFCLOG_E("read page failed, ret=%d", ret);
                return ret;
            }
            if (!osi_memcpy_s(write_buf, sizeof(write_buf), p_rsp->data, T2T_BYTES_PRE_BLOCK)) {
                NFCLOG_E("memcpy failed");
                return NCI_STATUS_EXT_COPY_FAILED;
            }
        }
        uint8_t copy_len = ndef_len_len - write_len;
        uint8_t curr_block_available = T2T_BYTES_PRE_BLOCK - ndef_len_offset_in_block;
        if (copy_len > curr_block_available) {
            copy_len = curr_block_available;
        }
        if (!osi_memcpy_s(write_buf + ndef_len_offset_in_block, curr_block_available, ndef_length_array + write_len, copy_len)) {
            NFCLOG_E("memcpy failed");
            return NCI_STATUS_EXT_COPY_FAILED;
        }
        ret = t2t_write_block(curr_block, write_buf, &p_rsp);
        if (ret != NCI_STATUS_OK) {
            NFCLOG_E("write block failed, ret=%d", ret);
            return ret;
        }
        curr_block++;
        write_len += copy_len;
        ndef_len_offset_in_block = 0;
    }

    if (write_len != ndef_len_len) {
        NFCLOG_E("ndef length update failed, write_len=%d, ndef_len_len=%d", write_len, ndef_len_len);
        return NCI_STATUS_EXT_FAILED;
    }
    return ret;
}

static tNCI_STATUS ndef_write_add_terminator_tlv(uint8_t *last_block, uint8_t offset_in_block, uint16_t block_no, tNCI_BUF *p_rsp) {
    tNCI_STATUS ret = NCI_STATUS_EXT_FAILED;
    if (offset_in_block > T2T_BYTES_PRE_BLOCK) {
        // NDEF已经充满了这个block，需要写入到下个Block
        uint8_t terminator_block[] = {T2T_TLV_TERM, 0x00, 0x00, 0x00};
        ret = t2t_write_block(block_no + 1, terminator_block, &p_rsp);
        if (ret != NCI_STATUS_OK) {
            NFCLOG_E("write block failed, ret=%d", ret);
            return ret;
        }
    } else {

        last_block[offset_in_block] = T2T_TLV_TERM;
        ret = t2t_write_block(block_no, last_block, &p_rsp);
        if (ret != NCI_STATUS_OK) {
            NFCLOG_E("write block failed, ret=%d", ret);
            return ret;
        }
    }
    return ret;
}
static tNCI_STATUS ndef_write(uint8_t *p_data, uint32_t data_len) {
    tT2T_INFO *p_t2t = &s_t2t_info;
    tNCI_STATUS ret = NCI_STATUS_EXT_FAILED;
    if (!p_t2t->is_ndef_detected) {
        NFCLOG_E("ndef not detected");
        return NCI_STATUS_EXT_FAILED;
    }
    if (p_t2t->ndef_len_start == 0) {
        NFCLOG_E("ndef tlv not found");
        return NCI_STATUS_EXT_FAILED;
    }
    if (p_t2t->hdr[T2T_CC3_RWA_BYTE] != T2T_CC3_RWA_RW) {
        NFCLOG_E("Write access not granted, cc3=0x%02X", p_t2t->hdr[T2T_CC3_RWA_BYTE]);
        return NCI_STATUS_EXT_REJECTED;
    }

    if (data_len > p_t2t->ndef_max_size) {
        NFCLOG_E("Cannot write NDEF of size greather than %d bytes, NDEF data length=%d", p_t2t->ndef_max_size, data_len);
        return NCI_STATUS_EXT_FAILED;
    }

    tT2T_INIT_TAG *p_init = find_tag_init_data(p_t2t->hdr[0], false, 0);
    if (p_init && p_init->is_opt) {
        NFCLOG_E("Cannot overwrite NDEF message on a OPT tag!");
        return NCI_STATUS_EXT_FAILED;
    }

    uint8_t len_field_len = 1;
    if (data_len > 0xFF) {
        // 长度大于0xFF，需要3个字节保存长度
        len_field_len = 3;
    }
    tNCI_BUF *rsp = NULL;
    // LEN字段 + NDEF数据
    uint16_t ndef_len = len_field_len + data_len;

    uint8_t *p_ndef = osi_calloc(ndef_len);
    if (!p_ndef) {
        NFCLOG_E("Allocate memory failed");
        ret = NCI_STATUS_EXT_ALLOC_FAILED;
    }

    if (!osi_memcpy_s(p_ndef + len_field_len, data_len, p_data, data_len)) {
        NFCLOG_E("Copy NDEF data failed");
        ret = NCI_STATUS_EXT_COPY_FAILED;
        goto cleanup;
    }

    uint8_t write_buf[T2T_BYTES_PRE_BLOCK] = {};
    uint16_t byte_offset = p_t2t->ndef_len_start;
    uint16_t write_len = 0;
    uint16_t remain_len = ndef_len - write_len;
    uint16_t block_no = byte_offset / T2T_BYTES_PRE_BLOCK;
    uint8_t *p_buf = &p_ndef[write_len];
    bool is_first_ndef_block = true;


    while (write_len < ndef_len && byte_offset < p_t2t->max_size) {
        // 一次循环写入一个block
        uint8_t offset_in_block = byte_offset % T2T_BYTES_PRE_BLOCK;
        block_no = byte_offset / T2T_BYTES_PRE_BLOCK;
        remain_len = ndef_len - write_len;
        uint8_t block_attr = p_t2t->attr[byte_offset / T2T_BYTES_PRE_ATTR_BYTE_CTRL];
        uint8_t attr_offset = byte_offset % T2T_BYTES_PRE_ATTR_BYTE_CTRL;
        if (attr_offset >= T2T_BYTES_PRE_BLOCK) {
            // attr_offset 超过一个block，由attr的高4bit控制这一个block
            block_attr = (block_attr >> 4) & 0x0F;
        } else {
            block_attr = block_attr & 0x0F;
        }

        p_buf = &p_ndef[write_len];

        if (block_attr == 0x0F) {
            // block_attr为0x0F表示整个block都不能写入NDEF数据，直接跳过此block
            byte_offset = (block_no + 1) << 2; // 直接跳转下一个block的起始地址
            continue;
        }

        if (block_attr != 0 || offset_in_block != 0) {
            // 满足以下条件任意一项时，需要先读取当前block再写入
            // 1. block_attr != 0 表示当前block中有byte不能写入NDEF数据
            // 2. offset_in_block != 0 表示当前写入开始地址不在block的起始位置
            // 3. remain_len < T2T_BYTES_PRE_BLOCK 表示剩余NDEF数据长度小于一个block
            if (write_len == 0) {
                // 第一个block直接从p_t2t->ndef_first_block中获取
                if (!osi_memcpy_s(write_buf, T2T_BYTES_PRE_BLOCK, p_t2t->ndef_first_block, T2T_BYTES_PRE_BLOCK)) {
                    NFCLOG_E("Copy NDEF first block failed");
                    ret = NCI_STATUS_EXT_COPY_FAILED;
                    goto cleanup;
                }
            } else {
                // 后续block需要从卡片中读取
                ret = t2t_read_page(block_no, &rsp);
                if (ret != NCI_STATUS_OK) {
                    goto cleanup;
                }
                if (!osi_memcpy_s(write_buf, T2T_BYTES_PRE_BLOCK, rsp->data, T2T_BYTES_PRE_BLOCK)) {
                    NFCLOG_E("Copy data failed");
                    ret = NCI_STATUS_EXT_COPY_FAILED;
                    goto cleanup;
                }
            }
            // 计算当前哪些字节是可以写入NDEF数据的，并填充到write_buf中
            for (uint8_t i = offset_in_block; i < T2T_BYTES_PRE_BLOCK && write_len < ndef_len; i++) {
                if ((block_attr & s_t2t_mask_bits[i]) == 0) {
                    // 非保留字节，可以写入NDEF数据
                    write_buf[i] = p_ndef[write_len++];
                }
            }

            p_buf = write_buf;
        } else if (remain_len < T2T_BYTES_PRE_BLOCK) {
            // 剩余NDEF数据长度小于一个block，不足的部分填充0
            if (!osi_memset_s(write_buf, T2T_BYTES_PRE_BLOCK, 0, T2T_BYTES_PRE_BLOCK)) {
                NFCLOG_E("memset failed");
                ret = NCI_STATUS_EXT_FAILED;
                goto cleanup;
            }
            if (!osi_memcpy_s(write_buf, T2T_BYTES_PRE_BLOCK, p_buf, remain_len)) {
                NFCLOG_E("Copy data failed");
                ret = NCI_STATUS_EXT_COPY_FAILED;
                goto cleanup;
            }
            write_len += remain_len;
            p_buf = write_buf;
        } else {
            // 直接写入一block的数据
            write_len += T2T_BYTES_PRE_BLOCK;
        }

        ret = t2t_write_block(block_no, p_buf, &rsp);
        if (ret != NCI_STATUS_OK) {
            goto cleanup;
        }

        if (is_first_ndef_block) {
            // 更新NDEF first block
            if (!osi_memcpy_s(p_t2t->ndef_first_block, T2T_BYTES_PRE_BLOCK, write_buf, T2T_BYTES_PRE_BLOCK)) {
                NFCLOG_E("Copy NDEF first block failed");
                ret = NCI_STATUS_EXT_COPY_FAILED;
                goto cleanup;
            }
        }

        byte_offset = (block_no + 1) << 2; // 直接跳转下一个block的起始地址
        is_first_ndef_block = false;
    }

    if (write_len != ndef_len) {
        NFCLOG_E("Write data failed, write len=%d, ndef_len=%d", write_len, ndef_len);
        ret = NCI_STATUS_EXT_FAILED;
        goto cleanup;
    }

    ret = ndef_Write_update_ndef_len(data_len, rsp);
    if (ret != NCI_STATUS_OK) {
        goto cleanup;
    }
    if (data_len < p_t2t->ndef_max_size) {
        ret = ndef_write_add_terminator_tlv(p_buf, remain_len, block_no, rsp);
        if (ret != NCI_STATUS_OK) {
            goto cleanup;
        }
    }

    p_t2t->ndef_value_len = data_len;
    p_t2t->ndef_value_start = p_t2t->ndef_len_start + len_field_len;

    ret = NCI_STATUS_OK;

cleanup:
    if (ret != NCI_STATUS_OK) {
        reset_t2t_info();
    }
    if (p_ndef) {
        osi_free(p_ndef);
    }
    free_nci_buf(rsp);
    return ret;
}

static tNCI_STATUS is_ndef_formatable() {
    return s_t2t_info.is_ndef_formatable ? NCI_STATUS_OK : NCI_STATUS_EXT_NOT_SUPPORTED;
}

static tNCI_STATUS set_tag_read_only(bool is_hard_lock) {
    /**
     * 1.检测NDEF detect状态
     * 2.写CC RWA Byte为只读，如果是软锁则到此结束，如果是硬锁则继续执行
     * 3.设置T2T Static Lock Byte为只读
     * 4.设置T2T Dynamic Lock Byte为只读
     */
    tT2T_INFO *p_t2t = &s_t2t_info;
    tNCI_BUF *rsp = NULL;
    uint8_t *p_lock_page = NULL;
    tNCI_STATUS ret = NCI_STATUS_EXT_FAILED;
    if (!p_t2t->is_ndef_detected) {
        NFCLOG_E("NDEF not detected");
        return NCI_STATUS_EXT_FAILED;
    }

    if ((p_t2t->hdr[T2T_CC3_RWA_BYTE] & T2T_CC3_RWA_RO) != T2T_CC3_RWA_RO) {
        // 写CC RWA Byte为只读
        p_t2t->hdr[T2T_CC3_RWA_BYTE] = T2T_CC3_RWA_RO;
        ret = t2t_write_block(T2T_CC_BLOCK_NO, &p_t2t->hdr[T2T_CC0_NMN_BYTE], &rsp);
        if (ret != NCI_STATUS_OK) {
            NFCLOG_E("write CC block failed, ret=%d", ret);
            goto cleanup;
        }
    }

    if (!is_hard_lock) {
        ret = NCI_STATUS_OK;
        goto cleanup;
    }

    // 后续是设置硬锁的逻辑

    // 设置T2T Static Lock Byte为只读
    p_t2t->hdr[T2T_STATIC_LOCK0_BYTE] = 0xFF;
    p_t2t->hdr[T2T_STATIC_LOCK1_BYTE] = 0xFF;
    uint8_t static_lock_block_no = T2T_STATIC_LOCK0_BYTE / T2T_BYTES_PRE_BLOCK;
    ret = t2t_write_block(static_lock_block_no, &p_t2t->hdr[static_lock_block_no * T2T_BYTES_PRE_BLOCK], &rsp);
    if (ret != NCI_STATUS_OK) {
        NFCLOG_E("write static lock block failed, ret=%d", ret);
        goto cleanup;
    }
    p_t2t->is_static_locked = true;

    // 设置T2T Dynamic Lock Byte为只读
    uint16_t dynamic_block_no = p_t2t->lock_bits_start / T2T_BYTES_PRE_BLOCK;
    uint8_t dynamic_block_offset = p_t2t->lock_bits_start % T2T_BYTES_PRE_BLOCK;
    uint8_t dynamic_byte_count = p_t2t->lock_bits_count / 8;
    if (p_t2t->lock_bits_count % 8 != 0) {
        dynamic_byte_count++;
    }

    uint8_t write_byte_count = 0;
    uint8_t write_buf[T2T_BYTES_PRE_BLOCK] = {0};

    while (write_byte_count < dynamic_byte_count) {
        // 每一轮循环写入一个block数据
        if (!osi_memset_s(write_buf, T2T_BYTES_PRE_BLOCK, 0, T2T_BYTES_PRE_BLOCK)) {
            NFCLOG_E("memset failed");
            ret = NCI_STATUS_EXT_FAILED;
            goto cleanup;
        }
        for (uint8_t i = dynamic_block_offset; i < T2T_BYTES_PRE_BLOCK && write_byte_count < dynamic_byte_count; i++) {
            write_buf[i] = 0xFF;
            write_byte_count++;
        }
        ret = t2t_write_block(dynamic_block_no, write_buf, &rsp);
        if (ret != NCI_STATUS_OK) {
            NFCLOG_E("write dynamic lock block failed, ret=%d", ret);
            goto cleanup;
        }
        dynamic_block_no++;
        dynamic_block_offset = 0;
    }
    // 更新lock attr为全1
    if (!osi_memset_s(p_t2t->lock_attr, p_t2t->lock_attr_len, 0xFF, p_t2t->lock_attr_len)) {
        NFCLOG_E("memset failed");
        ret = NCI_STATUS_EXT_FAILED;
        goto cleanup;
    }

cleanup:
    if (p_lock_page) {
        osi_free(p_lock_page);
    }
    free_nci_buf(rsp);
    return ret;
}
#endif // IS_FEATURE_ON(NCI_FEATURE_RW_NDEF)

tNCI_STATUS on_connect(tNCI_RW_TAG *p_tag) {
    (void) p_tag;
    reset_t2t_info();
#if IS_FEATURE_ON(NCI_FEATURE_RW_NDEF)
    tNCI_RF_TECH_PARAM_PA *p_pa = &p_tag->tech_params[p_tag->index].pa;
    uint8_t uid0 = p_tag->uid[0];
    bool is_ndef_formatable = false;
    if (uid0 == T2T_TAG_MUL_MID) {
        uint16_t atqa = (uint16_t)(p_pa->sens_res[0] << 8) | p_pa->sens_res[1];
        uint8_t sak = p_pa->sel_res;
        is_ndef_formatable = (atqa == T2T_ATQA_MUL) && (sak == 0x00 || sak == 0x04);
    } else if (uid0 == T2T_TAG_INFINEON_MID) {
        uint8_t uid1 = p_tag->uid[1];
        is_ndef_formatable = (uid1 & 0xF0) == 0x30;
    } else if (uid0 == T2T_TAG_KOVIO_MID) {
        is_ndef_formatable = true;
    }
    s_t2t_info.is_ndef_formatable = is_ndef_formatable;
#endif // IS_FEATURE_ON(NCI_FEATURE_RW_NDEF)
    return NCI_STATUS_OK;
}

tNCI_STATUS on_disconnect() {
    reset_t2t_info();
    return NCI_STATUS_OK;
}

static tNCI_STATUS presence_check() {
    tNCI_BUF *rsp = NULL;
    tNCI_STATUS ret = t2t_read_page(0, &rsp);
    if (ret != NCI_STATUS_OK) {
        goto cleanup;
    }
cleanup:
    free_nci_buf(rsp);
    return ret;
}

static tNCI_STATUS on_deselect(tNCI_RW_TAG *p_tag) {
    if (!p_tag) {
        NFCLOG_E("tag is null");
        return NCI_STATUS_EXT_INVALID_PARAM;
    }
    if (p_tag->interfaces[p_tag->index] != NCI_RF_INTERFACE_FRAME) {
        // 只有在Interface是Frame是才发送HALT命令
        return NCI_STATUS_OK;
    }
    uint8_t sleep_req_cmd[] = {0x50, 0x00};
    tNCI_BUF *cmd = alloc_nci_buf_with_cap(0, sizeof(sleep_req_cmd));
    if (!cmd) {
        NFCLOG_E("alloc sleep request cmd failed");
        return NCI_STATUS_EXT_ALLOC_FAILED;
    }
    ARRAY_TO_BUF(cmd, sleep_req_cmd, sizeof(sleep_req_cmd));
    tNCI_STATUS ret = rf_transmit_async(cmd);
    if (ret != NCI_STATUS_OK) {
        NFCLOG_E("send sleep request failed, ret=%d", ret);
    }
    free_nci_buf(cmd);
    return ret;
}

static tNCI_STATUS check_transceive_resp(uint8_t *p_rsp, uint16_t *p_rsp_len) {
    if (!p_rsp || !p_rsp_len || *p_rsp_len < 2) {
        NFCLOG_E("invalid param");
        return NCI_STATUS_EXT_INVALID_PARAM;
    }
    uint16_t rsp_len = *p_rsp_len;
    if (p_rsp[rsp_len - 1] != 0x00) {
        NFCLOG_E("t2t transceive failed, status=0x%02X", p_rsp[rsp_len - 1]);
        return NCI_STATUS_EXT_FAILED;
    }
    if (rsp_len == 2 && ((p_rsp[0] & 0x0F) != T2T_ACK)) {
        NFCLOG_E("t2t transceive failed, nak=0x%02X", p_rsp[0]);
        if (s_t2t_info.skip_check_nak) {
            NFCLOG_I("skip check nak");
            goto success;
        }
        return NCI_STATUS_EXT_FAILED;
    }
success:
    *p_rsp_len = rsp_len - 1; // 去掉最后一个状态字节
    return NCI_STATUS_OK;
}

tNCI_RW_TAG_API g_rw_t2t_api = {
    .max_retry_count = NCI_RW_DEFAULT_MAX_RETRY_COUNT,
    .on_connect = on_connect,
    .on_disconnect = on_disconnect,
    .on_deselect = on_deselect,
    .presence_check = presence_check,
    .check_transceive_resp = check_transceive_resp,
#if IS_FEATURE_ON(NCI_FEATURE_RW_NDEF)
    .ndef_detect = ndef_detect,
    .ndef_read = ndef_read,
    .ndef_format = ndef_format,
    .ndef_write = ndef_write,
    .is_ndef_formatable = is_ndef_formatable,
    .set_tag_read_only = set_tag_read_only,
#endif // IS_FEATURE_ON(NCI_FEATURE_NDEF)
};

#endif // IS_FEATURE_ON(NCI_FEATURE_RW_T2T)

